第7章 依存性注入
部品から製品を組み立てる
テスト駆動でよい部品ができる
IMO:鍵は作ると使うを分ける(作る=組み立てる)
使用と生成の分離 (Kindle版 p.293)
依存性注入とは
「オブジェクトが使う機能の実体を得る際、その解決を自力で行わず、常に外部から与えるようにすべし」という設計方針 (Kindle版 p.281)
例:FizzBuzzSequencePrinter(FizzBuzzアプリ)
NumberConverterの何らかのインスタンスとOutputInterfaceの何らかのインスタンスを外部からコンストラクタで受け取る(=依存性注入)
単体テストはインスタンスをモックにして、モックの呼び出しの検証になる
IMO:インターフェースから使い方はわかっている。実装の詳細は知らない
実装の詳細を知らないので、詳細の変更影響を受けない
こうして外部から具象インスタンスを与えられる形にしたものは、それ自身の責務以外に関心を払わなくて済む閉じた形になります。(Kindle版 pp.286-287)
構築は別の責務に分離された!
使われるオブジェクトは、自身がどのように組み立てられるかを気にしない (Kindle版 p.287)
生成 Factory
生成する知識を分けると、小さなメソッドがチェーンする(数珠つなぎ)
例:FizzBuzzAppFactory
FizzBuzzSequencePrinterを生成する
各メソッドはnewを一度だけ(=小さい)
IMO:テストも書きやすそう
チェーン=再帰的
DIを徹底することで、各クラスの実装は、外部のクラスの使用方法、つまりインターフェースにだけ依存する独立性の高い形になります。(Kindle版 p.291)
インターフェース(=使い方)への依存が望ましいのは、第5章 オブジェクト指向原則 SOLIDのISPより
「インターフェースは利用時の概念」!
別の例:ロギングライブラリ
注入されるloggerのdebugメソッドを呼ぶだけのほうがスッキリする(使い方は変わらない)
単体テストしやすいとDIしやすいには正の相関がある
DIコンテナ
オブジェクトの生成と構成を一般化したフレームワーク (Kindle版 p.296)
JavaではSpring IoC、Google Guice
PHPではSymfonyのServiceContainer(本書)
Pythonはinjectorが見つかった((触りたい)python-dependency-injectorもある)
宣言的なファイル設定などをもとに、インスタンス生成を行う
アノテーションを使う場合もある
先のFizzBuzzAppFactoryがやっていたのと同じことで、パフォーマンスの問題(重複生成)も解消された
SymfonyのServiceContainerでconfig/services.yamlを書く例
IMO:同じことをやるPythonライブラリはある?
IMO:機械学習でパラメタをyamlに定義するのは近い考え方?
実際のところ、現代のプログラミングでは、最初からDIコンテナを選択するのが普通です。(Kindle版 p.302)
IMO:ファクトリを実装しなくてよくなるので、開発捗りそう
サービスロケーターは、コンテナだがアンチパターン
外部から与えられていないオブジェクトを自主的に取りに行って使う (Kindle版 p.302)
単体テストしやすくない
IMO:「コンテナ」って語に説明がないけどなんなんだろう。容れ物?
オートワイヤリング
オブジェクト間の依存関係を自動的に結びつける (Kindle版 p.305)
IMO:Springで見た!
injectorは型ヒントから結びつけた
SymfonyのServiceContainerのyamlを最適化する例
今後クラスが増えても、自動決定できるならいちいち書き足す必要もなさそうです。(Kindle版 p.308)
アプリケーション固有の設定だけが残る
インスタンス間の自明な関係づけはDIコンテナのオートワイヤリングに任せる
オートワイヤリングで作業の独立性が高まる
インターフェースの実装が1つだけという点について
制御と依存を逆転させる目的があるのだから、多態にバリエーションがなくても、決して無意味なんかではありません。(Kindle版 p.311)